import fs from 'fs'
import eol from 'eol'
import { findFile } from './lib/file/find-file'
import { autoCommit } from './cm-content'
import { config } from './configs'
import { git } from './git/git'
import path from 'path'

/**
 * 版本号格式配置接口
 */
interface VersionConfig {
    /** 项目名称 */
    projectName: string
    /** 版本号字段路径 */
    versionPath: string[]
    /** 是否为数字类型版本 */
    isNumericVersion?: boolean
}

/**
 * 默认版本配置
 */
const VERSION_CONFIGS: VersionConfig[] = [
    {
        projectName: 'default',
        versionPath: ['version']
    },
    {
        projectName: '4399im',
        versionPath: ['asarVersion'],
        isNumericVersion: true
    },
    {
        projectName: '4399im-debug',
        versionPath: ['asarVersion'],
        isNumericVersion: true
    }
]

/**
 * 版本号正则表达式 - 支持语义化版本号
 * 匹配格式：x.y.z、x.y.z-alpha.1、x.y.z-beta.2、x.y.z-b123 等
 */
const VERSION_REGEX = /(\d+)\.(\d+)\.(\d+)(?:-(alpha|beta|rc|b)\.?(\d+))?/g

/**
 * 错误类型定义
 */
class VersionUpdateError extends Error {
    constructor(message: string, public readonly cause?: Error) {
        super(message)
        this.name = 'VersionUpdateError'
    }
}

/**
 * 更新字符串版本号
 * @param versionString 原版本号字符串
 * @returns 更新后的版本号字符串
 */
function updateStringVersion(versionString: string): string {
    try {
        // 检查是否包含构建号 (-b123 格式)
        const buildMatch = versionString.match(/^(.+)-b(\d+)$/)
        if (buildMatch) {
            const [, baseVersion, buildNumber] = buildMatch
            const newBuildNumber = parseInt(buildNumber, 10) + 1
            return `${baseVersion}-b${newBuildNumber}`
        }

        // 处理语义化版本号
        const versionMatch = versionString.match(/^(\d+)\.(\d+)\.(\d+)(?:-(alpha|beta|rc)\.?(\d+))?$/)
        if (versionMatch) {
            const [, major, minor, patch, prerelease, prereleaseNumber] = versionMatch

            if (prerelease && prereleaseNumber) {
                // 预发布版本号递增
                const newPrereleaseNumber = parseInt(prereleaseNumber, 10) + 1
                return `${major}.${minor}.${patch}-${prerelease}.${newPrereleaseNumber}`
            } else {
                // 补丁版本号递增
                const newPatch = parseInt(patch, 10) + 1
                return `${major}.${minor}.${newPatch}`
            }
        }

        throw new VersionUpdateError(`无效的版本号格式: ${versionString}`)
    } catch (error) {
        throw new VersionUpdateError(
            `更新版本号失败: ${versionString}`,
            error instanceof Error ? error : new Error(String(error))
        )
    }
}

/**
 * 更新版本号（支持字符串和数字类型）
 * @param version 原版本号
 * @returns 更新后的版本号
 */
function updateVersion<T extends string | number>(version: T): T {
    if (typeof version === 'number') {
        return (version + 1) as T
    }
    return updateStringVersion(version) as T
}

/**
 * 在字符串内容中更新版本号
 * @param content 文件内容
 * @returns 包含新版本号和更新后内容的对象
 */
export function updateVersionInString(content: string): { newVersion: string; newContent: string } {
    let newVersion = ''
    let matchCount = 0

    const newContent = content.replace(VERSION_REGEX, (match) => {
        matchCount++
        newVersion = updateStringVersion(match)
        return newVersion
    })

    if (matchCount === 0) {
        throw new VersionUpdateError('在内容中未找到有效的版本号')
    }

    return { newVersion, newContent }
}

/**
 * 版本修改器基类
 */
abstract class VersionModifier {
    protected jsonData: any

    constructor(jsonData: any) {
        this.jsonData = jsonData
    }

    /**
     * 获取当前版本号
     */
    abstract getVersion(): string | number

    /**
     * 设置新版本号
     */
    abstract setVersion(version: string | number): void

    /**
     * 应用版本号更新
     */
    applyUpdate(): void {
        const currentVersion = this.getVersion()
        const newVersion = updateVersion(currentVersion)
        this.setVersion(newVersion)
    }
}

/**
 * 默认版本修改器
 */
class DefaultVersionModifier extends VersionModifier {
    constructor(jsonData: any) {
        super(jsonData)
    }

    getVersion(): string {
        return this.jsonData.version || '0.0.0'
    }

    setVersion(version: string): void {
        this.jsonData.version = version
    }
}

/**
 * 特殊项目版本修改器
 */
class CustomVersionModifier extends VersionModifier {
    private config: VersionConfig

    constructor(jsonData: any, config: VersionConfig) {
        super(jsonData)
        this.config = config
    }

    getVersion(): string | number {
        let current = this.jsonData

        for (const path of this.config.versionPath) {
            if (current && typeof current === 'object' && path in current) {
                current = current[path]
            } else {
                throw new VersionUpdateError(`版本号路径不存在: ${this.config.versionPath.join('.')}`)
            }
        }

        // 对于数字版本类型，还需要根据 buildENV 来获取具体值
        if (this.config.isNumericVersion && this.jsonData.buildENV) {
            const env = this.jsonData.buildENV
            if (current && typeof current === 'object' && env in current) {
                return current[env]
            }
            throw new VersionUpdateError(`构建环境 ${env} 的版本号不存在`)
        }

        return current
    }

    setVersion(version: string | number): void {
        let current = this.jsonData
        const pathCopy = [...this.config.versionPath]
        const lastKey = pathCopy.pop()!

        // 导航到目标对象
        for (const path of pathCopy) {
            if (!current[path]) {
                current[path] = {}
            }
            current = current[path]
        }

        // 设置版本号
        if (this.config.isNumericVersion && this.jsonData.buildENV) {
            const env = this.jsonData.buildENV
            if (!current[lastKey]) {
                current[lastKey] = {}
            }
            current[lastKey][env] = version
        } else {
            current[lastKey] = version
        }
    }
}

/**
 * 创建版本修改器
 */
function createVersionModifiers(jsonData: any): VersionModifier[] {
    const modifiers: VersionModifier[] = []

    // 添加默认版本修改器
    modifiers.push(new DefaultVersionModifier(jsonData))

    // 根据项目名称添加特殊版本修改器
    if (jsonData.name) {
        const config = VERSION_CONFIGS.find(cfg => cfg.projectName === jsonData.name)
        if (config && config.projectName !== 'default') {
            modifiers.push(new CustomVersionModifier(jsonData, config))
        }
    }

    return modifiers
}

/**
 * 更新 JSON 内容中的版本号
 * @param content JSON 文件内容
 * @returns 更新后的 JSON 字符串
 */
function updateVersionInJson(content: string): string {
    try {
        const jsonData = JSON.parse(content)
        const modifiers = createVersionModifiers(jsonData)

        // 应用所有版本修改器
        modifiers.forEach(modifier => {
            try {
                modifier.applyUpdate()
            } catch (error) {
                console.warn(`版本修改器应用失败:`, error)
            }
        })

        return eol.auto(JSON.stringify(jsonData, null, 2))
    } catch (error) {
        throw new VersionUpdateError(
            'JSON 解析或处理失败',
            error instanceof Error ? error : new Error(String(error))
        )
    }
}

/**
 * 更新文件中的版本号
 * @param filePath 文件路径
 * @returns 新的版本号
 */
export function updateVersionInFile(filePath: string): string {
    try {
        // 检查文件是否存在
        if (!fs.existsSync(filePath)) {
            throw new VersionUpdateError(`文件不存在: ${filePath}`)
        }

        // 读取文件内容
        const content = fs.readFileSync(filePath, 'utf-8')

        if (filePath.endsWith('.json')) {
            // 处理 JSON 文件
            const newContent = updateVersionInJson(content)
            fs.writeFileSync(filePath, newContent, 'utf-8')

            // 从更新后的内容中提取版本号返回
            const jsonData = JSON.parse(newContent)
            return jsonData.version || 'unknown'
        } else {
            // 处理其他文件类型
            const { newVersion, newContent } = updateVersionInString(content)
            fs.writeFileSync(filePath, newContent, 'utf-8')
            return newVersion
        }
    } catch (error) {
        if (error instanceof VersionUpdateError) {
            throw error
        }
        throw new VersionUpdateError(
            `文件处理失败: ${filePath}`,
            error instanceof Error ? error : new Error(String(error))
        )
    }
}

export function autoPush() {
    const submodules = config.submodules || []
    
    // 子模块优先推送
    if (submodules.length > 0) {
        const cwd = process.cwd()
        const submodulesPath = submodules.map(submodule => path.resolve(cwd, submodule))
        submodulesPath.forEach(submodulePath => {
            git.setCWD(submodulePath)
            git.push()
        })
        git.setCWD(cwd)
    }

    // 推送主模块
    git.push()
}

export function autoUpdateCommit(commit = '', push = false) {
    const versionFile = findFile(['package.json'])
    if (versionFile) {
        const newVersion = updateVersionInFile(versionFile)
        const submodules = config.submodules || []

        // 子模块优先提交版本号
        if (submodules.length > 0) {
            const cwd = process.cwd()
            const submodulesPath = submodules.map(submodule => path.resolve(cwd, submodule))
            submodulesPath.forEach(submodulePath => {
                git.setCWD(submodulePath)
                try {
                    autoCommit(`[version] ${newVersion} ${commit}`.trim())
                } catch (error) {
                    console.error(`子模块(${submodulePath}) 提交版本号失败`)
                    console.error(error)
                }
            })
            git.setCWD(cwd)
        }
        autoCommit(`[version] ${newVersion} ${commit}`.trim())

        if (push) {
            autoPush()
        }
    } else {
        console.error('未找到版本号文件')
    }
}